#include "CandlestickChart.h"
#include <yyjson.h>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <cmath>
#include <vector>
#include <cmath>
#include <algorithm>

CandlestickChart::CandlestickChart(uint16_t id) : id(id)
{
    yyjson_doc *doc = yyjson_read_file("NVDA.json", 0, NULL, NULL);

    CandlestickChartData data = Finviz::CandlestickChartAnalyze(yyjson_doc_get_root(doc));

    this->SetCandlestickChartData(data);

    yyjson_doc_free(doc);
}

void CandlestickChart::SetCandlestickChartData(const CandlestickChartData &data)
{
    this->data = data;
    this->last_index = data.Items.size() - 1;
}

void CandlestickChart::Draw()
{
    std::string title = std::to_string(this->id) + '-' + this->symbal;

    ImGui::Begin(title.c_str(), NULL);

    const ImVec2 windowsize = ImGui::GetWindowSize();

    Begin("Test", ImVec2(windowsize.x - 16, windowsize.y - 100), ImGuiChildFlags_FrameStyle, ImGuiWindowFlags_None);

    ImGui::End();
}

void CandlestickChart::MouseCheck(const int &number_items)
{
    auto io = Application::GetIO();

    if (io->MouseWheel != 0.0f)
    {
        if (io->MouseWheel > 0.0f)
        {
            if (multiple < 4)
            {
                multiple += 0.1;
            }
        }
        else
        {
            if (multiple > 0.5)
            {
                multiple -= 0.1;
            }
        }
    }

    // 鼠标拖动检测
    if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
    {
        // 获取鼠标拖动的偏移量
        ImVec2 dragDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left);

        // 如果水平拖动超过一定阈值（例如 10 像素），则调整 last_index
        if (abs(dragDelta.x) > 10.0f)
        {
            if (dragDelta.x > 0.0f)
            {
                // 向右拖动
                if (last_index > number_items)
                {
                    last_index--;
                }
            }
            else
            {
                // 向左拖动
                if (last_index != (data.Items.size() - 1))
                {
                    last_index++;
                }
            }

            // 重置拖动偏移量，避免连续触发
            ImGui::ResetMouseDragDelta(ImGuiMouseButton_Left);
        }
    }
}

bool IsMouseInCanvas(const ImVec2 &canvas_pos, const ImVec2 &canvas_size, const ImVec2 &mouse_pos)
{

    // 计算 canvas 的边界
    float canvas_x_min = canvas_pos.x;
    float canvas_x_max = canvas_pos.x + canvas_size.x;
    float canvas_y_min = canvas_pos.y;
    float canvas_y_max = canvas_pos.y + canvas_size.y;

    // 判断鼠标位置是否在 canvas 内
    return (mouse_pos.x >= canvas_x_min && mouse_pos.x <= canvas_x_max &&
            mouse_pos.y >= canvas_y_min && mouse_pos.y <= canvas_y_max);
}

std::string TimestampToString(uint64_t timestamp, const std::string &format = "%Y-%m-%d %H:%M:%S")
{
    // 将时间戳转换为 time_t 类型
    std::time_t t = static_cast<std::time_t>(timestamp);

    // 将 time_t 转换为 tm 结构体
    std::tm tm = *std::localtime(&t);

    // 使用 std::put_time 将 tm 格式化为字符串
    std::stringstream ss;
    ss << std::put_time(&tm, format.c_str());

    return ss.str();
}

void CandlestickChart::Begin(const char *str_id, const ImVec2 &size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags)
{
    // 开始绘画子窗口
    ImGui::BeginChild(str_id, size_arg, child_flags, window_flags);

    // 获取当前窗口的绘制列表，用于绘制图形
    auto draw_list = ImGui::GetWindowDrawList();

    // 获取画布的屏幕坐标
    ImVec2 canvas_pos = ImGui::GetCursorScreenPos();

    // 获取画布的可用区域大小
    ImVec2 canvas_size = ImGui::GetContentRegionAvail();

    // 获取鼠标的当前位置
    ImVec2 mouse_pos = ImGui::GetMousePos();

    // 如果数据为空，直接返回
    if (data.Items.empty())
        return;

    // 计算能绘制的 K 线数量
    int number_items = static_cast<int>(canvas_size.x / (this->multiple * 10)); // 根据缩放因子计算 K 线数量

    // 确保 number_items 不超过数据的总量
    number_items = std::min(number_items, static_cast<int>(data.Items.size()));

    // 计算绘制的起始索引
    int start_index = this->last_index - number_items + 1;

    // 确保 start_index 不小于 0
    start_index = std::max(start_index, 0);

    // 计算每根 K 线的宽度
    float bar_width = canvas_size.x / number_items; // 动态计算 K 线宽度

    // 计算价格范围，找到最低价和最高价
    float min_price = data.Items[start_index].low;
    float max_price = data.Items[start_index].high;
    for (int i = start_index; i <= this->last_index; i++)
    {
        const auto &item = data.Items[i];
        min_price = std::min(min_price, item.low);
        max_price = std::max(max_price, item.high);
    }

    // 计算时间范围，找到最小时间和最大时间
    uint64_t min_time = data.Items[start_index].timestamp;
    uint64_t max_time = data.Items[this->last_index].timestamp;

    // 绘制价格轴，分为 5 个刻度
    for (int i = 0; i <= 5; i++)
    {
        // 计算当前刻度的价格
        float price = min_price + (max_price - min_price) * (i / 5.0f);

        // 计算当前刻度在画布上的 y 坐标
        float y = canvas_pos.y + canvas_size.y * (1 - (price - min_price) / (max_price - min_price));

        // 绘制价格刻度线
        draw_list->AddLine(ImVec2(canvas_pos.x, y), ImVec2(canvas_pos.x + canvas_size.x, y), IM_COL32(100, 100, 100, 50));

        // 绘制价格文本
        draw_list->AddText(ImVec2(canvas_pos.x, y - 10), IM_COL32(255, 255, 255, 255), std::to_string(price).c_str());
    }

    // 绘制时间轴，分为 5 个刻度
    for (int i = 0; i <= 5; i++)
    {
        // 计算当前刻度的时间
        uint64_t time = min_time + (max_time - min_time) * (i / 5.0f);

        // 计算当前刻度在画布上的 x 坐标
        float x = canvas_pos.x + canvas_size.x * (i / 5.0f);

        // 绘制时间刻度线
        draw_list->AddLine(ImVec2(x, canvas_pos.y), ImVec2(x, canvas_pos.y + canvas_size.y), IM_COL32(100, 100, 100, 50));

        // 将时间戳转换为可读格式
        std::time_t t = static_cast<std::time_t>(time);
        char buffer[20];
        std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M", std::localtime(&t));

        // 绘制时间文本
        draw_list->AddText(ImVec2(x, canvas_pos.y + canvas_size.y + 5), IM_COL32(255, 255, 255, 255), buffer);
    }

    // 遍历绘制的 K 线数据，绘制每根 K 线
    for (int i = start_index; i <= this->last_index; i++)
    {
        const auto &item = data.Items[i];

        // 计算 K 线的位置
        float x = canvas_pos.x + (i - start_index) * bar_width;
        float y_open = canvas_pos.y + canvas_size.y * (1 - (item.open - min_price) / (max_price - min_price));
        float y_close = canvas_pos.y + canvas_size.y * (1 - (item.close - min_price) / (max_price - min_price));
        float y_high = canvas_pos.y + canvas_size.y * (1 - (item.high - min_price) / (max_price - min_price));
        float y_low = canvas_pos.y + canvas_size.y * (1 - (item.low - min_price) / (max_price - min_price));

        // 根据开盘价和收盘价决定 K 线颜色
        ImU32 color = (item.close >= item.open) ? IM_COL32(0, 255, 0, 255) : IM_COL32(255, 0, 0, 255);

        // 绘制 K 线的上下影线
        draw_list->AddLine(ImVec2(x + bar_width / 2, y_high), ImVec2(x + bar_width / 2, y_low), color);

        // 绘制 K 线的实体部分
        draw_list->AddRectFilled(ImVec2(x, y_open), ImVec2(x + bar_width, y_close), color);

        // 判断鼠标是否悬停在当前 K 线上
        if (mouse_pos.x >= x && mouse_pos.x <= x + bar_width &&
            mouse_pos.y >= canvas_pos.y && mouse_pos.y <= canvas_pos.y + canvas_size.y)
        {
            ImGui::BeginTooltip();

            // 显示开盘价、收盘价、最高价、最低价、成交量等信息
            ImGui::Text("Open: %.2f", item.open);
            ImGui::Text("Close: %.2f", item.close);
            ImGui::Text("High: %.2f", item.high);
            ImGui::Text("Low: %.2f", item.low);
            ImGui::Text("Volume: %llu", item.volume);
            ImGui::Text("Time: %s", TimestampToString(item.timestamp, "%H:%M:%S").c_str());

            // 结束工具提示
            ImGui::EndTooltip();
        }
    }

    // 如果鼠标在画布区域内，绘制鼠标位置的辅助线
    if (IsMouseInCanvas(canvas_pos, canvas_size, mouse_pos))
    {
        draw_list->AddLine(ImVec2(canvas_pos.x, mouse_pos.y), ImVec2(canvas_pos.x + canvas_size.x, mouse_pos.y), IM_COL32(100, 100, 100, 100));
        draw_list->AddLine(ImVec2(mouse_pos.x, canvas_pos.y), ImVec2(mouse_pos.x, canvas_pos.y + canvas_size.y), IM_COL32(100, 100, 100, 100));
        this->MouseCheck(number_items);
    }

    // 绘制最新价格的辅助线
    float last_price = canvas_pos.y + canvas_size.y * (1 - (data.last_price - min_price) / (max_price - min_price));
    draw_list->AddLine(ImVec2(canvas_pos.x, last_price), ImVec2(canvas_pos.x + canvas_size.x, last_price), IM_COL32(200, 100, 100, 100));

    // 结束子窗口
    ImGui::EndChild();
}